studiocms
Version:
Astro Native CMS for AstroDB. Built from the ground up by the Astro community.
287 lines (286 loc) • 9.56 kB
JavaScript
import { User } from "studiocms:auth/lib";
import { apiResponseLogger } from "studiocms:logger";
import { Notifications } from "studiocms:notifier";
import { SDKCore } from "studiocms:sdk";
import { UserPermissionLevel } from "@withstudiocms/auth-kit/types";
import {
AllResponse,
createEffectAPIRoutes,
createJsonResponse,
Effect,
genLogger,
OptionsResponse,
parseAPIContextJson,
Schema
} from "../../../../../../effect.js";
import { verifyAuthTokenFromHeader } from "../../utils/auth-token.js";
class JSONData extends Schema.Class("JSONData")({
rank: Schema.Union(
Schema.Literal("owner"),
Schema.Literal("admin"),
Schema.Literal("editor"),
Schema.Literal("visitor"),
Schema.Literal("unknown")
)
}) {
}
const { ALL, DELETE, GET, OPTIONS, PATCH } = createEffectAPIRoutes(
{
GET: (ctx) => genLogger("studioCMS:rest:v1:users:[id]:GET")(function* () {
const [sdk, user, userUtils] = yield* Effect.all([
SDKCore,
verifyAuthTokenFromHeader(ctx),
User
]);
if (user instanceof Response) {
return user;
}
const { rank } = user;
if (rank !== "owner" && rank !== "admin") {
return apiResponseLogger(401, "Unauthorized");
}
const { id } = ctx.params;
if (!id) {
return apiResponseLogger(400, "Invalid form data, id is required");
}
const existingUser = yield* sdk.GET.users.byId(id);
if (!existingUser) {
return apiResponseLogger(404, "User not found");
}
const { avatar, createdAt, email, name, permissionsData, updatedAt, url, username } = existingUser;
const existingUserRank = permissionsData?.rank ?? "visitor";
const data = {
avatar,
createdAt,
email,
id,
name,
rank: existingUserRank,
updatedAt,
url,
username
};
const loggedInUser = yield* sdk.GET.users.byId(user.userId);
if (!loggedInUser || loggedInUser === void 0) {
return apiResponseLogger(400, "User Error");
}
const permissionLevelInput = {
isLoggedIn: true,
user: loggedInUser,
permissionLevel: loggedInUser.permissionsData?.rank ?? "visitor"
};
const userPermissionLevel = yield* userUtils.getUserPermissionLevel(permissionLevelInput);
const requiredPerms = () => {
switch (existingUserRank) {
case "owner":
return UserPermissionLevel.owner;
case "admin":
return UserPermissionLevel.admin;
case "editor":
return UserPermissionLevel.editor;
case "visitor":
return UserPermissionLevel.visitor;
default:
return UserPermissionLevel.unknown;
}
};
const isAllowed = userPermissionLevel > requiredPerms();
if (!isAllowed) {
return apiResponseLogger(401, "Unauthorized");
}
return createJsonResponse(data);
}),
PATCH: (ctx) => genLogger("studioCMS:rest:v1:users:[id]:PATCH")(function* () {
const [sdk, user, userUtils, notifier] = yield* Effect.all([
SDKCore,
verifyAuthTokenFromHeader(ctx),
User,
Notifications
]);
if (user instanceof Response) {
return user;
}
const { rank } = user;
if (rank !== "owner" && rank !== "admin") {
return apiResponseLogger(401, "Unauthorized");
}
const { id } = ctx.params;
if (!id) {
return apiResponseLogger(400, "Invalid form data, id is required");
}
const existingUser = yield* sdk.GET.users.byId(id);
if (!existingUser) {
return apiResponseLogger(400, "User not found");
}
const { permissionsData } = existingUser;
const existingUserRank = permissionsData?.rank ?? "admin";
const loggedInUser = yield* sdk.GET.users.byId(user.userId);
if (!loggedInUser || loggedInUser === void 0) {
return apiResponseLogger(400, "User Error");
}
const permissionLevelInput = {
isLoggedIn: true,
user: loggedInUser,
permissionLevel: loggedInUser.permissionsData?.rank ?? "visitor"
};
const userPermissionLevel = yield* userUtils.getUserPermissionLevel(permissionLevelInput);
const requiredPerms = () => {
switch (existingUserRank) {
case "owner":
return UserPermissionLevel.owner;
case "admin":
return UserPermissionLevel.admin;
case "editor":
return UserPermissionLevel.editor;
case "visitor":
return UserPermissionLevel.visitor;
default:
return UserPermissionLevel.unknown;
}
};
const isAllowed = userPermissionLevel > requiredPerms();
if (!isAllowed) {
return apiResponseLogger(401, "Unauthorized");
}
const { rank: newRank } = yield* parseAPIContextJson(ctx, JSONData);
if (!newRank) {
return apiResponseLogger(400, "Missing field: Rank is required");
}
const requiredPermsForNewRank = (() => {
switch (newRank) {
case "owner":
return UserPermissionLevel.owner;
case "admin":
return UserPermissionLevel.admin;
case "editor":
return UserPermissionLevel.editor;
case "visitor":
return UserPermissionLevel.visitor;
default:
return UserPermissionLevel.unknown;
}
})();
if (userPermissionLevel <= requiredPermsForNewRank) {
return apiResponseLogger(403, "Forbidden");
}
const updateRank = yield* sdk.UPDATE.permissions({
user: id,
rank: newRank
});
if (!updateRank) {
return apiResponseLogger(400, "Failed to update rank");
}
const updatedUser = yield* sdk.GET.users.byId(id);
if (!updatedUser) {
return apiResponseLogger(400, "Failed to get updated user");
}
const {
avatar,
createdAt,
email,
name,
permissionsData: newPermissionsData,
updatedAt,
url,
username
} = updatedUser;
const updatedUserRank = newPermissionsData?.rank ?? "unknown";
const data = {
avatar,
createdAt,
email,
id,
name,
rank: updatedUserRank,
updatedAt,
url,
username
};
yield* notifier.sendUserNotification("account_updated", id);
yield* notifier.sendAdminNotification("user_updated", username);
return createJsonResponse(data);
}).pipe(Notifications.Provide),
DELETE: (ctx) => genLogger("studioCMS:rest:v1:users:[id]:DELETE")(function* () {
const [sdk, user, userUtils, notifier] = yield* Effect.all([
SDKCore,
verifyAuthTokenFromHeader(ctx),
User,
Notifications
]);
if (user instanceof Response) {
return user;
}
const { rank } = user;
if (rank !== "owner" && rank !== "admin") {
return apiResponseLogger(401, "Unauthorized");
}
const { id } = ctx.params;
if (!id) {
return apiResponseLogger(400, "Invalid form data, id is required");
}
if (id === user.userId) {
return apiResponseLogger(400, "Cannot delete your own account");
}
const existingUser = yield* sdk.GET.users.byId(id);
if (!existingUser) {
return apiResponseLogger(400, "User not found");
}
const { permissionsData } = existingUser;
const existingUserRank = permissionsData?.rank ?? "admin";
const loggedInUser = yield* sdk.GET.users.byId(user.userId);
if (!loggedInUser || loggedInUser === void 0) {
return apiResponseLogger(400, "User Error");
}
const permissionLevelInput = {
isLoggedIn: true,
user: loggedInUser,
permissionLevel: loggedInUser.permissionsData?.rank ?? "visitor"
};
const userPermissionLevel = yield* userUtils.getUserPermissionLevel(permissionLevelInput);
const requiredPerms = () => {
switch (existingUserRank) {
case "owner":
return UserPermissionLevel.owner;
case "admin":
return UserPermissionLevel.admin;
case "editor":
return UserPermissionLevel.editor;
case "visitor":
return UserPermissionLevel.visitor;
default:
return UserPermissionLevel.unknown;
}
};
const isAllowed = userPermissionLevel > requiredPerms();
if (!isAllowed) {
return apiResponseLogger(401, "Unauthorized");
}
const response = yield* sdk.DELETE.user(id);
if (!response) {
return apiResponseLogger(400, "Failed to delete user");
}
if (response.status === "error") {
return apiResponseLogger(400, response.message);
}
yield* notifier.sendAdminNotification("user_deleted", existingUser.username);
return apiResponseLogger(200, response.message);
}).pipe(Notifications.Provide),
OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ["GET", "PATCH", "DELETE"] })),
ALL: () => Effect.try(() => AllResponse())
},
{
cors: { methods: ["GET", "PATCH", "DELETE", "OPTIONS"] },
onError: (error) => {
console.error("API Error:", error);
return createJsonResponse({ error: "Something went wrong" }, { status: 500 });
}
}
);
export {
ALL,
DELETE,
GET,
JSONData,
OPTIONS,
PATCH
};